//
//  UIView+YHExtension.swift
//  Adorbee
//
//  Created by amovision on 2024/11/26.
//

import UIKit
#if canImport(SnapKit)
import SnapKit
#endif

// MARK: - UIView 扩展

public extension UIView {
  // 原有功能保持不变
  internal func addSubviews(_ subviews: [UIView]) {
    subviews.forEach { addSubview($0) }
  }

  convenience init(color: UIColor?, radius: CGFloat = 0) {
    self.init()
    backgroundColor = color
    if !isMember(of: UIView.self) {
      layer.masksToBounds = true
    }
    layer.cornerRadius = radius
  }

  func addSubviews(_ subviews: UIView...) {
    subviews.forEach { addSubview($0) }
  }

  func addCorner(_ radius: CGFloat, borderWidth: CGFloat = 0, borderColor: UIColor = .clear) {
    if !isMember(of: UIView.self) { layer.masksToBounds = true }
    layer.cornerRadius = radius
    if borderWidth > 0 {
      layer.borderColor = borderColor.cgColor
      layer.borderWidth = borderWidth
    }
  }

  var onDarkMode: Bool {
    traitCollection.userInterfaceStyle == .dark
  }

  enum SeparateDirection { case top, left, bottom, right }
  func addLine(_ direction: UIView.SeparateDirection, _ lineWidth: CGFloat, margin: CGFloat = 0, offset: CGPoint = .zero, color: UIColor = .separator) {
#if canImport(SnapKit)
    let line = UIView()
    line.backgroundColor = color
    addSubview(line)
    line.snp.makeConstraints { make in
      switch direction {
      case .top:
        make.top.equalTo(margin)
        make.left.equalTo(offset.x)
        make.right.equalTo(-offset.y)
        make.height.equalTo(lineWidth)
      case .left:
        make.left.equalTo(margin)
        make.top.equalTo(offset.x)
        make.bottom.equalTo(-offset.y)
        make.width.equalTo(lineWidth)
      case .bottom:
        make.bottom.equalTo(-margin)
        make.left.equalTo(offset.x)
        make.right.equalTo(-offset.y)
        make.height.equalTo(lineWidth)
      case .right:
        make.right.equalTo(-margin)
        make.top.equalTo(offset.x)
        make.bottom.equalTo(-offset.y)
        make.width.equalTo(lineWidth)
      }
    }
#endif
  }

// SnapKit 约束相关
#if canImport(SnapKit)
  func makeConstraints(on view: UIView? = nil, _ closure: (ConstraintMaker) -> Void) {
    if let view, !isDescendant(of: view) {
      view.addSubview(self)
    }
    snp.makeConstraints(closure)
  }

  func remakeConstraints(on view: UIView? = nil, _ closure: (ConstraintMaker) -> Void) {
    if let view, !isDescendant(of: view) {
      view.addSubview(self)
    }
    snp.remakeConstraints(closure)
  }

  func updateConstraints(on view: UIView? = nil, _ closure: (ConstraintMaker) -> Void) {
    if let view, !isDescendant(of: view) {
      view.addSubview(self)
    }
    snp.updateConstraints(closure)
  }
#endif

  // 布局属性
  var maxX: CGFloat {
    get { frame.maxX }
    set { frame.origin.x = newValue - frame.width }
  }

  var minX: CGFloat {
    get { frame.minX }
    set { frame.origin.x = newValue }
  }

  var maxY: CGFloat {
    get { frame.maxY }
    set { frame.origin.y = newValue - frame.height }
  }

  var minY: CGFloat {
    get { frame.minY }
    set { frame.origin.y = newValue }
  }

  var midX: CGFloat {
    get { frame.midX }
    set { center.x = newValue }
  }

  var midY: CGFloat {
    get { frame.midY }
    set { center.y = newValue }
  }
}

// MARK: - UIView 手势相关扩展

public extension UIView {
  /// 添加点击手势
  /// - Parameters:
  ///   - taps: 点击次数（默认1次）
  ///   - touches: 触摸点数（默认1点）
  ///   - block: 手势处理闭包
  func addTapHandler(taps: Int = 1, touches: Int = 1, block: @escaping (UITapGestureRecognizer) -> Void) {
    isUserInteractionEnabled = true
    let gesture = UITapGestureRecognizer(taps: taps, touches: touches, block: block)
    addGestureRecognizer(gesture)
  }

  func addDoubleTap(block: @escaping (UITapGestureRecognizer) -> Void) {
    isUserInteractionEnabled = true
    let gesture = UITapGestureRecognizer(taps: 2, touches: 1, block: block)
    addGestureRecognizer(gesture)
  }

  func addTapAction(_ action: Selector?, target: Any?) {
    isUserInteractionEnabled = true
    let gesture = UITapGestureRecognizer(target: target, action: action)
    addGestureRecognizer(gesture)
  }

  /// 移除所有手势
  func removeAllGestureRecognizers() {
    gestureRecognizers?.forEach { removeGestureRecognizer($0) }
  }
}

public extension UIView {
  var yh_cornerRadius: CGFloat {
    get {
      return layer.cornerRadius
    } set {
      if !isMember(of: UIView.self) { layer.masksToBounds = true }
      layer.cornerRadius = newValue
    }
  }

  var yh_borderWidth: CGFloat {
    get {
      return layer.borderWidth
    } set {
      layer.borderWidth = newValue
    }
  }

  var yh_borderColor: UIColor? {
    get {
      return layer.borderColor.flatMap(UIColor.init(cgColor:))
    } set {
      layer.borderColor = newValue?.cgColor
    }
  }

  var yh_shadowColor: UIColor? {
    get {
      return layer.shadowColor.flatMap(UIColor.init(cgColor:))
    } set {
      layer.shadowColor = newValue?.cgColor
    }
  }

  var yh_shadowOpacity: Float {
    get {
      return layer.shadowOpacity
    } set {
      layer.shadowOpacity = newValue
    }
  }

  var yh_shadowOffset: CGSize {
    get {
      return layer.shadowOffset
    } set {
      layer.shadowOffset = newValue
    }
  }

  var yh_shadowRadius: CGFloat {
    get {
      return layer.shadowRadius
    } set {
      layer.shadowRadius = newValue
    }
  }

  /**
    根据给定的固定维度（宽度或高度），计算视图的自适应尺寸。

    这个方法对于在将视图实际添加到视图层级之前，预先计算其尺寸非常有用（例如，在 UITableView 中计算 cell 高度）。

    要使此方法能正确工作，该视图必须已经设置了完整的、无歧义的内部 Auto Layout 约束，
    以便能够从内容推导出其内在尺寸。

    - Parameter dimension: 一个 `SizingDimension` 枚举，指定是宽度固定（`.fixedWidth(value)`）、
                           高度固定（`.fixedHeight(value)`），还是两者都不固定（`.unconstrained`）。

    - Returns: 一个 `CGSize`，其中包含计算出的自适应尺寸。
   */
  func adaptiveSize(basedOn dimension: SizingDimension) -> CGSize {
    // 根据传入的维度，准备 systemLayoutSizeFitting 所需的参数
    let targetSize: CGSize
    let horizontalPriority: UILayoutPriority
    let verticalPriority: UILayoutPriority

    switch dimension {
    case .fixedWidth(let width):
      // 目标：计算高度。宽度是已知的、必须满足的。
      targetSize = CGSize(width: width, height: UIView.layoutFittingCompressedSize.height)
      horizontalPriority = .required
      verticalPriority = .fittingSizeLevel

    case .fixedHeight(let height):
      // 目标：计算宽度。高度是已知的、必须满足的。
      targetSize = CGSize(width: UIView.layoutFittingCompressedSize.width, height: height)
      horizontalPriority = .fittingSizeLevel
      verticalPriority = .required

    case .unconstrained:
      // 目标：计算最小尺寸。宽度和高度都应尽可能贴合内容。
      targetSize = UIView.layoutFittingCompressedSize
      horizontalPriority = .fittingSizeLevel
      verticalPriority = .fittingSizeLevel
    }

    // 调用核心方法进行计算
    return systemLayoutSizeFitting(
      targetSize,
      withHorizontalFittingPriority: horizontalPriority,
      verticalFittingPriority: verticalPriority
    )
  }
  
  func adaptiveHeight(_ width: CGFloat) -> CGFloat {
    adaptiveSize(basedOn: .fixedWidth(width)).height
  }
  
  func adaptiveWidth(_ height: CGFloat) -> CGFloat {
    adaptiveSize(basedOn: .fixedHeight(height)).width
  }
  
}

/// 用于描述在计算自适应尺寸时，哪个维度是固定的。
public enum SizingDimension {
  /// 固定宽度，计算自适应高度。
  case fixedWidth(CGFloat)

  /// 固定高度，计算自适应宽度。
  case fixedHeight(CGFloat)

  /// 宽高都不固定，计算完全由内容压缩决定的最小尺寸。
  case unconstrained
}
